using System;
using System.Collections;
using System.Collections.Generic;

namespace EntityKit.Runtime
{
    /// <summary>
    /// 可观察队列类，当队列内容发生变化时会触发相应的事件
    /// </summary>
    /// <typeparam name="T">队列元素的类型</typeparam>
    public class BindableQueue<T> : IEnumerable<T>, IEnumerable
    {
        private Queue<T> mQueue = new Queue<T>();
        
        /// <summary>
        /// 当元素入队时触发的事件
        /// </summary>
        public event Action<T> OnItemEnqueued;
        
        /// <summary>
        /// 当元素出队时触发的事件
        /// </summary>
        public event Action<T> OnItemDequeued;
        
        /// <summary>
        /// 当队列被清空时触发的事件
        /// </summary>
        public event Action OnCleared;
        
        /// <summary>
        /// 当队列内容发生任何变化时触发的事件
        /// </summary>
        public event Action OnChanged;
        
        /// <summary>
        /// 获取队列中元素的数量
        /// </summary>
        public int Count => mQueue.Count;
        
        /// <summary>
        /// 将元素添加到队列的末尾
        /// </summary>
        /// <param name="item">要入队的元素</param>
        public void Enqueue(T item)
        {
            mQueue.Enqueue(item);
            OnItemEnqueued?.Invoke(item);
            OnChanged?.Invoke();
        }
        
        /// <summary>
        /// 移除并返回位于队列开始处的元素
        /// </summary>
        /// <returns>位于队列开始处的元素</returns>
        public T Dequeue()
        {
            T item = mQueue.Dequeue();
            OnItemDequeued?.Invoke(item);
            OnChanged?.Invoke();
            return item;
        }
        
        /// <summary>
        /// 返回位于队列开始处的元素但不将其移除
        /// </summary>
        /// <returns>位于队列开始处的元素</returns>
        public T Peek()
        {
            return mQueue.Peek();
        }
        
        /// <summary>
        /// 确定队列中是否包含特定元素
        /// </summary>
        /// <param name="item">要在队列中定位的元素</param>
        /// <returns>如果在队列中找到item，则为true；否则为false</returns>
        public bool Contains(T item)
        {
            return mQueue.Contains(item);
        }
        
        /// <summary>
        /// 清空队列中的所有元素
        /// </summary>
        public void Clear()
        {
            mQueue.Clear();
            OnCleared?.Invoke();
            OnChanged?.Invoke();
        }
        
        /// <summary>
        /// 将队列中的元素复制到一个新数组中
        /// </summary>
        /// <returns>包含队列中元素的数组</returns>
        public T[] ToArray()
        {
            return mQueue.ToArray();
        }
        
        /// <summary>
        /// 获取一个枚举器，用于遍历队列
        /// </summary>
        /// <returns>可用于遍历队列的枚举器</returns>
        public IEnumerator<T> GetEnumerator()
        {
            return mQueue.GetEnumerator();
        }
        
        /// <summary>
        /// 获取一个枚举器，用于遍历队列
        /// </summary>
        /// <returns>可用于遍历队列的枚举器</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        
        /// <summary>
        /// 返回队列中所有元素的字符串表示形式
        /// </summary>
        /// <returns>队列的字符串表示形式</returns>
        public override string ToString()
        {
            return $"BindableQueue<{typeof(T).Name}> (Count: {Count})";
        }
    }
}